热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

字面|山路_Window与其管理者的秘密

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Window与其管理者的秘密相关的知识,希望对你有一定的参考价值。Window,字面意义即窗口࿰

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Window与其管理者的秘密相关的知识,希望对你有一定的参考价值。


Window,字面意义即窗口,在android中,所有的视图都是通过Window来呈现的,Window是View的直接管理者。

Window是一个抽象类,具体实现是PhoneWindow。对Wndow的管理工作操作都是通过它的Manager–>WindowManager来做的,然而WindowManager也只是走个形式,真正的执行者是WindowManagerService,WindowManager通过提交工单的形式(IPC)交个WindowManagerService执行。

WindowManager管理Window的方式也很简单,常用的只有三种方法–>增删改(crud工程师),即addView(),updateViewLayout(),removeView()。这三个方法定义在ViewManager中,WIndowManager正是继承了ViewManager。

/**
* path: /frameworks/base/core/java/android/view/ViewManager.java
*/

public interface ViewManager
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);

接下来看看WindowManager是如何将安排Window安排的明明白白的
本文分析的Android源码版本:android-10.0.0_r40


传送门


  • WindowManager的管理手段
    • 增加Window的手段(addView())
    • 干掉Window的手段(removeView())
    • 更新Window的手段(updateViewLayout())

  • Window是如何诞生的
    • Window如何在Activity中诞生
    • Window如何在Dialog中诞生
    • Window如何在Toast中诞生
      • Toast的显示过程
      • Toast的隐藏过程
      • 总结




WindowManager的管理手段

每个Window对应一个View和ViewRootImpl,Window和View通过ViewRootImpl建立联系,所以Window是以View的形式存在的

管理Window,需要借助WindowManager提供的方法,WindowManager是一个接口,真正的实现类是WindowManagerImpl,WindowManagerImpl中对这三个操作的实现如下:

/**
*path: /frameworks/base/core/java/android/view/WindowManagerImpl.java
*/

public final class WindowManagerImpl implements WindowManager
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params)
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());

@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params)
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);

@Override
public void removeView(View view)
mGlobal.removeView(view, false);


从上述的源码中可以看到WindowManagerImpl并没有亲自处理这些操作,而是全部交给了它的秘书(WindowManagerGlobal)来做,WindowManagerImpl这种工作方式被称为桥接模式,WindowManagerGlobal通过单例模式向外提供实例,

/**
* path: /frameworks/base/core/java/android/view/WindowManagerGlobal.java
*/

public final class WindowManagerGlobal
@UnsupportedAppUsage
private static WindowManagerGlobal sDefaultWindowManager;
private WindowManagerGlobal()

//单例模式,对外返回唯一实例
@UnsupportedAppUsage
public static WindowManagerGlobal getInstance()
synchronized (WindowManagerGlobal.class)
if (sDefaultWindowManager == null)
sDefaultWindowManager = new WindowManagerGlobal();

return sDefaultWindowManager;




增加Window的手段(addView())

WindowManagerGlobal 的addView() 方法源码如下:

/**
* path: /frameworks/base/core/java/android/view/WindowManagerGlobal.java
*/

//存储所有Window对应的View
@UnsupportedAppUsage
private final ArrayList<View> mViews &#61; new ArrayList<View>();
//存储所有Window对应的ViewRootImpl
&#64;UnsupportedAppUsage
private final ArrayList<ViewRootImpl> mRoots &#61; new ArrayList<ViewRootImpl>();
//存储所有Window所对应的布局参数
&#64;UnsupportedAppUsage
private final ArrayList<WindowManager.LayoutParams> mParams &#61; new ArrayList<WindowManager.LayoutParams>();
//存储正在被删除的View对象(调用removeView()&#xff0c;但删除操作还未完成的Window)
private final ArraySet<View> mDyingViews &#61; new ArraySet<View>();
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId)
/* 1.检查参数的合法性&#xff0c;若是子Window还需调整布局参数 */
if (view &#61;&#61; null)
throw new IllegalArgumentException("view must not be null");

if (display &#61;&#61; null)
throw new IllegalArgumentException("display must not be null");

if (!(params instanceof WindowManager.LayoutParams))
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");

final WindowManager.LayoutParams wparams &#61; (WindowManager.LayoutParams) params;
if (parentWindow !&#61; null)
parentWindow.adjustLayoutParamsForSubWindow(wparams);
else
// If there&#39;s no parent, then hardware acceleration for this view is
// set from the application&#39;s hardware acceleration setting.
final Context context &#61; view.getContext();
if (context !&#61; null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) !&#61; 0)
wparams.flags |&#61; WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;


/* 第一步end */
/********************************************************/
/*2.创建ViewRootImpl&#xff0c;并将View加入到列表中*/
ViewRootImpl root;
View panelParentView &#61; null;
synchronized (mLock)
// Start watching for system property changes.
if (mSystemPropertyUpdater &#61;&#61; null)
mSystemPropertyUpdater &#61; new Runnable()
&#64;Override public void run()
synchronized (mLock)
for (int i &#61; mRoots.size() - 1; i >&#61; 0; --i)
mRoots.get(i).loadSystemProperties();



;
SystemProperties.addChangeCallback(mSystemPropertyUpdater);

int index &#61; findViewLocked(view, false);
if (index >&#61; 0)
if (mDyingViews.contains(view))
// Don&#39;t wait for MSG_DIE to make it&#39;s way through root&#39;s queue.
mRoots.get(index).doDie();
else
throw new IllegalStateException("View " &#43; view
&#43; " has already been added to the window manager.");

// The previous removeView() had not completed executing. Now it has.

// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >&#61; WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <&#61; WindowManager.LayoutParams.LAST_SUB_WINDOW)
final int count &#61; mViews.size();
for (int i &#61; 0; i < count; i&#43;&#43;)
if (mRoots.get(i).mWindow.asBinder() &#61;&#61; wparams.token)
panelParentView &#61; mViews.get(i);



root &#61; new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
/*第二步end*/
/********************************************************/
/*3.通过ViewRootImpl来更新界面并完成对Window的添加*/
// do this last because it fires off messages to start doing things
try
root.setView(view, wparams, panelParentView, userId);
catch (RuntimeException e)
// BadTokenException or InvalidDisplayException, clean up.
if (index >&#61; 0)
removeViewLocked(index, true);

throw e;

/*第三步end*/
/********************************************************/


WindowManagerGlobal 的addView() 方法主要做了这几件事&#xff1a;


  • 检查参数的合法性&#xff0c;若是子Window还需调整布局参数
  • 创建ViewRootImpl&#xff0c;并将View加入到列表中(列表的类型和作用已标注在源码中)
  • 通过ViewRootImpl来更新界面并完成对Window的添加
    这一步是通过ViewRootImpl的setView()来实现的&#xff0c;setView()内部通过requestLayout()来完成异步刷新请求(在requestLayout()方法中&#xff0c;scheduleTraversals()是View绘制的入口)&#xff0c;之后借助WindowSession的addToDisplayAsUser()方法来完成Window的添加&#xff0c;源码如下&#xff1a;

/**
* path: /frameworks/base/core/java/android/view/ViewRootImpl.java
*/

/**
* We have one child
*/

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView)
setView(view, attrs, panelParentView, UserHandle.myUserId());

/**
* We have one child
*/

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId)
synchronized (this)
if (mView &#61;&#61; null)
mView &#61; view;
mAttachInfo.mDisplayState &#61; mDisplay.getState();
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
mViewLayoutDirectionInitial &#61; mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
if (mWindowAttributes.packageName &#61;&#61; null)
mWindowAttributes.packageName &#61; mBasePackageName;

mWindowAttributes.privateFlags |&#61;
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
attrs &#61; mWindowAttributes;
setTag();
if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
& WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) !&#61; 0
&& (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) &#61;&#61; 0)
Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");

// Keep track of the actual window flags supplied by the client.
mClientWindowLayoutFlags &#61; attrs.flags;
setAccessibilityFocus(null, null);
if (view instanceof RootViewSurfaceTaker)
mSurfaceHolderCallback &#61;
((RootViewSurfaceTaker)view).willYouTakeTheSurface();
if (mSurfaceHolderCallback !&#61; null)
mSurfaceHolder &#61; new TakenSurfaceHolder();
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
mSurfaceHolder.addCallback(mSurfaceHolderCallback);


// Compute surface insets required to draw at specified Z value.
// TODO: Use real shadow insets for a constant max Z.
if (!attrs.hasManualSurfaceInsets)
attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);

CompatibilityInfo compatibilityInfo &#61; mDisplay.getDisplayAdjustments().getCompatibilityInfo();
mTranslator &#61; compatibilityInfo.getTranslator();
// If the application owns the surface, don&#39;t enable hardware acceleration
if (mSurfaceHolder &#61;&#61; null)
// While this is supposed to enable only, it can effectively disable
// the acceleration too.
enableHardwareAcceleration(attrs);
final boolean useMTRenderer &#61; MT_RENDERER_AVAILABLE
&& mAttachInfo.mThreadedRenderer !&#61; null;
if (mUseMTRenderer !&#61; useMTRenderer)
// Shouldn&#39;t be resizing, as it&#39;s done only in window setup,
// but end just in case.
endDragResizing();
mUseMTRenderer &#61; useMTRenderer;


boolean restore &#61; false;
if (mTranslator !&#61; null)
mSurface.setCompatibilityTranslator(mTranslator);
restore &#61; true;
attrs.backup();
mTranslator.translateWindowLayout(attrs);

if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" &#43; attrs);
if (!compatibilityInfo.supportsScreen())
attrs.privateFlags |&#61; WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
mLastInCompatMode &#61; true;

mSoftInputMode &#61; attrs.softInputMode;
mWindowAttributesChanged &#61; true;
mAttachInfo.mRootView &#61; view;
mAttachInfo.mScalingRequired &#61; mTranslator !&#61; null;
mAttachInfo.mApplicationScale &#61; mTranslator &#61;&#61; null ? 1.0f : mTranslator.applicationScale;
if (panelParentView !&#61; null)
mAttachInfo.mPanelParentWindowToken
&#61; panelParentView.getApplicationWindowToken();

mAdded &#61; true;
int res; /* &#61; WindowManagerImpl.ADD_OKAY; */
/*完成异步刷新请求*/
/********************************************************/
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
/********************************************************/
InputChannel inputChannel &#61; null;
if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) &#61;&#61; 0)
inputChannel &#61; new InputChannel();

mForceDecorViewVisibility &#61; (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) !&#61; 0;
/*通过WindowSession来添加Window*/
/********************************************************/
try
mOrigWindowType &#61; mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes &#61; true;
collectViewAttributes();
adjustLayoutParamsForCompatibility(mWindowAttributes);
res &#61; mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
setFrame(mTmpFrame);
catch (RemoteException e)
mAdded &#61; false;
mView &#61; null;
mAttachInfo.mRootView &#61; null;
inputChannel &#61; null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
finally
if (restore)
attrs.restore();


/********************************************************/
if (mTranslator !&#61; null)
mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);

mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
mAttachInfo.mAlwaysConsumeSystemBars &#61;
(res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) !&#61; 0;
mPendingAlwaysConsumeSystemBars &#61; mAttachInfo.mAlwaysConsumeSystemBars;
mInsetsController.onStateChanged(mTempInsets);
mInsetsController.onControlsChanged(mTempControls);
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " &#43; mWindow);
if (res < WindowManagerGlobal.ADD_OKAY)
mAttachInfo.mRootView &#61; null;
mAdded &#61; false;
mFallbackEventHandler.setView(null)

推荐阅读
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • SmartRefreshLayout自定义头部刷新和底部加载
    1.添加依赖implementation‘com.scwang.smartrefresh:SmartRefreshLayout:1.0.3’implementation‘com.s ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文详细介绍了cisco路由器IOS损坏时的恢复方法,包括进入ROMMON模式、设置IP地址、子网掩码、默认网关以及使用TFTP服务器传输IOS文件的步骤。 ... [详细]
  • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 涉及的知识点-ViewGroup的测量与布局-View的测量与布局-滑动冲突的处理-VelocityTracker滑动速率跟踪-Scroller实现弹性滑动-屏幕宽高的获取等实现步 ... [详细]
  • 我收到这个错误.我怎么能在我的情况下解决这个问题?Bitmapcannotberesolvedtoatype发生错误的行publicvoidonPageStart ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了如何使用elementui分页组件进行分页功能的改写,只需一行代码即可调用。通过封装分页组件,避免在每个页面都写跳转请求的重复代码。详细的代码示例和使用方法在正文中给出。 ... [详细]
  • 认识Cutestrap,一个轻量级CSS框架
    CutestrapisabrandnewCSSframework.ThisarticlepresentsCutestrap’sfeaturesandputstheframework ... [详细]
author-avatar
雯颜哥_135
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有